#include "seqiot.h"
#include "model.h"
#include "sqlite.h"

static void debug_object(const char *type, object_t *obj) {
    printf("==========%s(id=%d, name=%s)==========\n", type, obj->id, obj->name);
}

static void debug_thing_model(product_t *product) {
    debug_object("product", &product->super);

    for (int j = 0; j < sizeof(product->thing_model) / sizeof(product->thing_model[0]); ++j) {
        for (int k = 0; k < vector_size(&product->thing_model[j]); ++k) {
            thing_model_t *tag = vector_get(&product->thing_model[j], k);
            unsigned int tag_id = tag->segment * 0x1000 + tag->super.id + 1;
            printf("id=%d/%xH, name=%s", tag_id, tag_id, tag->super.name);
            printf(", seg=%d, tag=%d, metric=%s", tag->segment, tag->super.id, tag->metric);
            if (protocol_is_dlt645(product->protocol)) {
                printf(", di=%08x, digits=%d, decimals=%d", tag->data_identifier, tag->digit, tag->decimal);
            } else if (protocol_is_modbus(product->protocol)) {
                printf(", data_type=%d, writable=%d", tag->data_type, tag->writable);
                printf(", swap_byte=%d, swap_word=%d", tag->swap_byte, tag->swap_word);
                printf(", value_type=%d, mul_u=%d, mul_i=%d", tag->value_type, tag->mul_u, tag->mul_i);
                printf(", scale=%lf, adjust=%lf", tag->scale, tag->adjust);
            }
            printf(", time_tag=%d, time_type=%d", tag->time_tag, tag->time_type);
        }
    }
    printf("\n\n");
}

static void debug_thing_models(seqiot_t *seqiot) {
    for (int i = 0; i < vector_size(&seqiot->products); ++i) {
        product_t *product = vector_get(&seqiot->products, i);
        if (!product->_loaded) continue;

        debug_thing_model(product);
    }
}

static void debug_uplink(uplink_t *uplink) {
    debug_object("uplink", &uplink->super);

    printf("rtu=%d, payload=%d", uplink->rtu, uplink->payload);
    printf(", remote=%s:%d", uplink->remote_address.addr, uplink->remote_address.port);
    printf(", timeout=%d, heartbeat=%d", uplink->timeout, uplink->heartbeat);
    printf(", username=%s, password=%s, client_id=%s", uplink->username, uplink->password, uplink->client_id);
    printf(", product=%s, device=%s, secret=%s", uplink->product_key, uplink->device_key, uplink->device_secret);
    printf("\n\n");
}

static void debug_uplinks(seqiot_t *seqiot) {
    for (int i = 0; i < vector_size(&seqiot->uplinks); ++i) {
        uplink_t *uplink = vector_get(&seqiot->channels, i);
        debug_uplink(uplink);
    }
}

static void debug_channel(channel_t *channel) {
    debug_object("channel", &channel->super);

    printf("protocol=%d, timeout=%d", channel->protocol, channel->timeout);
    if (channel_is_serial(channel->type)) {
        serial_params_t *serial = &channel->serial;
        printf(", serial=%s, baud=%d(%d:%d:%d)", serial->device,
               serial->baud, serial->data_bits, serial->parity, serial->stop_bits);
    } else if (ct_tcpip == channel->type) {
        tcpip_params_t *tcpip = &channel->tcpip;
        printf(", ip=%s, port=%d", tcpip->addr, tcpip->port);
    }
    printf("\n\n");
}

static void debug_channels(seqiot_t *seqiot) {
    for (int i = 0; i < vector_size(&seqiot->channels); ++i) {
        channel_t *channel = vector_get(&seqiot->channels, i);
        debug_channel(channel);
    }
}

static void debug_device(device_t *device) {
    debug_object("device", &device->super);

    printf("channel=%d, product=%d", device->channel, device->product);
    printf(", slave=%d, shift=%d", device->slave_id, device->shift_idx);
    printf(", u0=%d, i0=%d, ubb=%d, ibb=%d",
           device->u0, device->i0, device->ubb, device->ibb);
    printf(", u_decimal=%d, i_decimal=%d, p_decimal=%d",
           device->u_decimal, device->i_decimal, device->p_decimal);
    printf("\n\n");
}

static void debug_devices(seqiot_t *seqiot) {
    for (int i = 0; i < vector_size(&seqiot->channels); ++i) {
        channel_t *channel = vector_get(&seqiot->channels, i);
        debug_object("channel", &channel->super);

        for (int j = 0; j < vector_size(&channel->devices); ++j) {

            device_t *device = vector_get(&channel->devices, j);
            debug_device(device);
        }
    }
}

int main(int argc, char *argv[]) {
    int channel = 0;
    int uplink = 0;
    const char *filename = NULL;

    for (int i = 1; i < argc; ++i) {
        if (!strcmp("--file", argv[i])) {
            filename = argv[++i];
            break;
        } else if (!strcmp("--channel", argv[i])) {
            channel = atoi(argv[++i]);
            break;
        } else if (!strcmp("--uplink", argv[i])) {
            uplink = atoi(argv[++i]);
            break;
        } else {
            fprintf(stderr,
                    "usage: %s --help "
                    "--file <filename> --channel <channel_id> --uplink <uplink_id>\n",
                    argv[0]);
            return EXIT_FAILURE;
        }
    }

    seqiot_t *seqiot = seqiot_new();
    read_config(seqiot, filename, channel, uplink);

    debug_uplinks(seqiot);
    debug_channels(seqiot);
    debug_devices(seqiot);
    debug_thing_models(seqiot);

    seqiot_free(seqiot);
    z_debug();

    return EXIT_SUCCESS;
}
